package com.hezuti.common.utils;

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.zip.GZIPInputStream;
import java.util.zip.GZIPOutputStream;

public class StringUtil {
	private static final int UBYTE_INT = Byte.MAX_VALUE+1;
	private static final int UBYTE_ALL = Byte.MAX_VALUE+UBYTE_INT+1;
	
	public static byte[] getMemoryByte(String src) {
		int len = src.length() << 1;
		byte[] bytes = new byte[len];
		for(int i = 0; i < src.length(); ++i) {
			char c = src.charAt(i);
			bytes[i<<1] = (byte) (c >> 8);
			bytes[(i<<1)+1] = (byte) (c & 0xff);
		}
		return bytes;
	}
	
	public static byte[] zipStringToBytes(String input) throws IOException {
	    ByteArrayOutputStream bos = new ByteArrayOutputStream();
	    BufferedOutputStream bufos = new BufferedOutputStream(new GZIPOutputStream(bos));
	    bufos.write(input.getBytes());
	    bufos.close();
	    byte[] retval= bos.toByteArray();
	    bos.close();
	    return retval;
	}
	
	public static String unzipStringFromBytes(byte[] bytes) throws IOException {
	    ByteArrayInputStream bis = new ByteArrayInputStream(bytes);
	    BufferedInputStream bufis = new BufferedInputStream(new GZIPInputStream(bis));
	    ByteArrayOutputStream bos = new ByteArrayOutputStream();
	    byte[] buf = new byte[1024];
	    int len;
	    while((len = bufis.read(buf)) > 0) {
	    	bos.write(buf, 0, len);
	    }
	    String retval = bos.toString();
	    bis.close();
	    bufis.close();
	    bos.close();
	    return retval;
	}
	
	public static int width(String src) {
		int ascii = 0;
		byte[] srcBytes = getMemoryByte(src);
		for(int i = 0; i < srcBytes.length; i++) {
			if(srcBytes[i] == 0) {
				ascii++;
			}
		}
		return (src.length()-(ascii>>1));
	}
	
	public static String[] split(String src, String des) {
		if(src == null) {
			return null;
		} else if(des == null || des.length() <=0) {
			String[] res = new String[1];
			res[0] = src;
			return res;
		}
		
		List<String> list = new ArrayList<String>();
		
		byte[] srcBytes = getMemoryByte(src);
		byte[] desBytes = getMemoryByte(des);
		int len_s = srcBytes.length;
		int len_d = desBytes.length;
		
		int i, j, pos = 0;
		long[] next = new long[UBYTE_ALL];
		for(j = 0; j < UBYTE_ALL; ++j) {
	        next[j] = len_d;
	    }
		int last = len_d-1;
	    for(j = 0; j < last; ++j) {
	        next[desBytes[j]+UBYTE_INT] = last-j;
	    }
	    
	    int start = 0;
	    while(pos+last < len_s) {
	        i = pos;
	        for(j = 0; j <= last; ++j, ++i) {
	            if(srcBytes[i] != desBytes[j]) {
	            	pos += next[srcBytes[pos+last]+UBYTE_INT];
	            	pos = (pos+1)&(~0x1);//if pos is odd, pos should plus 1
	                break;
	            }
	        }
	        if(j > last) {
	        	int idx = pos >> 1;
	        	list.add(src.substring(start, idx));
	        	start = idx+des.length();
	        	pos += len_d;
	        }
	    }
	    if(start > 0) {
	    	if(start < src.length()) {
	    		list.add(src.substring(start));
	    	}
	    } else {
	    	//not found
	    	list.add(src);
	    }
	    return (String[]) list.toArray(new String[0]);
	}
	
	public static int indexOf(String src, String des) {
		if(src == null || des == null || src.length() < des.length() || src.length() == 0 || des.length() == 0) {
			return -1;
		}
		
		if(src.length() < UBYTE_ALL || des.length() == 1) {
			return src.indexOf(des);
		}
		
		byte[] srcBytes = getMemoryByte(src);
		byte[] desBytes = getMemoryByte(des);
		int len_s = srcBytes.length;
		int len_d = desBytes.length;
		
		int i, j, pos = 0;
		long[] next = new long[UBYTE_ALL];
		for(j = 0; j < UBYTE_ALL; ++j) {
	        next[j] = len_d;
	    }
		int last = len_d-1;
	    for(j = 0; j < last; ++j) {
	        next[desBytes[j]+UBYTE_INT] = last-j;
	    }
	    while(pos+last < len_s) {
	        i = pos;
	        for(j = 0; j <= last; ++j, ++i) {
	            if(srcBytes[i] != desBytes[j]) {
	            	pos += next[srcBytes[pos+last]+UBYTE_INT];
	            	pos = (pos+1)&(~0x1);//if pos is odd, pos should plus 1
	                break;
	            }
	        }
	        if(j > last) {
	            return pos >> 1;
	        }
	    }
		
		return -1;
	}
	
	public static String replaceAll(String src, String des, String rep) {
		if(src == null || des == null || src.length() < des.length() || src.length() == 0 || des.length() == 0) {
			return src;
		}
		
		byte[] srcBytes = getMemoryByte(src);
		byte[] desBytes = getMemoryByte(des);
		int len_s = srcBytes.length;
		int len_d = desBytes.length;
		
		int i, j, pos = 0;
		long[] next = new long[UBYTE_ALL];
		for(j = 0; j < UBYTE_ALL; ++j) {
	        next[j] = len_d;
	    }
		int last = len_d-1;
	    for(j = 0; j < last; ++j) {
	        next[desBytes[j]+UBYTE_INT] = last-j;
	    }
	    
	    StringBuffer buf = new StringBuffer();
	    if(rep == null) {
	    	rep = "";
	    }
	    int start = 0;
	    while(pos+last < len_s) {
	        i = pos;
	        for(j = 0; j <= last; ++j, ++i) {
	            if(srcBytes[i] != desBytes[j]) {
	            	pos += next[srcBytes[pos+last]+UBYTE_INT];
	            	pos = (pos+1)&(~0x1);//if pos is odd, pos should plus 1
	                break;
	            }
	        }
	        if(j > last) {
	        	int idx = pos >> 1;
	        	buf.append(src.substring(start, idx)).append(rep);
	        	start = idx+des.length();
	        	pos += len_d;
	        }
	    }
	    if(start > 0) {
	    	if(start < src.length()) {
	    		buf.append(src.substring(start));
	    	}
	    	return buf.toString();
	    }
	    
	    return src;
	}
	
	public static String replaceAll(String src, HashMap map) {
		StringBuffer buf = new StringBuffer();
		int start = 0;
		for(int i = 0; i < src.length(); i++) {
			char c = src.charAt(i);
			String r = (String) map.get(c);
			if(r != null) {
				buf.append(src.substring(start, i)).append(r);
				start = i+1;
			}
		}
		if(start < src.length()) {
			buf.append(src.substring(start));
		}
		return buf.toString();
	}
	
	public static String replaceFirst(String src, String des, String rep) {
		if(src != null && des != null && src.length() >= des.length()) {
			int idx = indexOf(src, des);
			if(idx >= 0) {
				if(rep == null) {
					rep = "";
				}
				return src.substring(0, idx)+rep+src.substring(idx+des.length());
			}
		}
		return src;
	}
	
	public static String escapeForAnd(String s) {
		if (s == null)
            return "";
        StringBuffer sb = new StringBuffer();
        for (int i = 0; i < s.length(); i++) {
            char ch = s.charAt(i);
            if ((int) ch < 32) {
                continue;
            } else if (ch == '&' && 
            		s.indexOf("&amp;", i) != i && 
            		s.indexOf("&lt;", i) != i && 
            		s.indexOf("&gt;", i) != i && 
            		s.indexOf("&quot;", i) != i && 
            		s.indexOf("&apos;", i) != i &&
            		s.indexOf("&nbsp;", i) != i && 
            		s.indexOf("&#", i) != i) {
                sb.append("&amp;");
            } else {
                sb.append(ch);
            }
        }
        return sb.toString();
	}
	
	public static String escape(String s) {
        if (s == null)
            return "";
        StringBuffer sb = new StringBuffer();
        for (int i = 0; i < s.length(); i++) {
            char ch = s.charAt(i);
            if ((int) ch < 32) {
                continue;
            }
            if (ch == '<') {
                sb.append("&lt;");
            }
            else if (ch == '>') {
                sb.append("&gt;");
            }
            else if (ch == '\'') {
                sb.append("&apos;");
            }
            else if (ch == '"') {
                sb.append("&quot;");
            }
            else if (ch == '&' && 
            		s.indexOf("&amp;", i) != i && 
            		s.indexOf("&lt;", i) != i && 
            		s.indexOf("&gt;", i) != i && 
            		s.indexOf("&quot;", i) != i && 
            		s.indexOf("&apos;", i) != i &&
            		s.indexOf("&#", i) != i) {
                sb.append("&amp;");
            }
            else {
                sb.append(ch);
            }
        }
        return sb.toString();
    }

	public static void main(String[] argv) {
		String in = "\"爱情买卖\"相关铃声[共3条]:<br/>";
		try {
			System.out.println(in.length());
			System.out.println(in.getBytes().length);
			byte[] bytes = zipStringToBytes(in);
			System.out.println(bytes.length);
			String out = null;
			long total = 0, n = 10000;
			for(int i = 0; i < n; i++) {
				long start = System.currentTimeMillis();
				out = unzipStringFromBytes(bytes);
				long end = System.currentTimeMillis();
				total += end-start;
			}
			System.out.println(((float)total)/n);
			System.out.println(out.length());
			//System.out.println(out);
		} catch (IOException e) {
			e.printStackTrace();
		}
		//System.out.println(width("abc./我们【]="));
		/*
		String src = "a测试ab测试abc测";
		String des = "ab";
		String rep = "o";
		
		String[] res = split(src, des);
		for(int i = 0; i < res.length; i++) {
			System.out.println(res[i]);
		}
		*/
		//String[] res = src.split(des);
		
		//System.out.println(indexOf(src, des));
		//System.out.println(replaceFirst(src, des, rep));
		//System.out.println(replaceAll(src, des, rep));
		/*
		long start, end, my = 0, java = 0, n = 10000;
		for(int i = 0; i < n; i++) {
			start = System.currentTimeMillis();
			//indexOf(src, des);
			//replaceFirst(src, des, rep);
			replaceAll(src, des, rep);
			end = System.currentTimeMillis();
			my += end-start;
			//System.out.print(end-start+"->");
			
			start = System.currentTimeMillis();
			//src.indexOf(des);
			//src.replaceFirst(des, rep);
			src.replaceAll(des, rep);
			end = System.currentTimeMillis();
			java += end-start;
			//System.out.println(end-start);
		}
		System.out.println((float)my/n+"->"+(float)java/n);
		*/
	}

	public static boolean isNull(String str) {
		if(str==null||"".equals(str.trim()))return true;
		return false;
	}
}